#pragma once

#include<iostream>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<functional>

#include"Log.hpp"
#include"InetAddr.hpp"
#include"PthreadPool.hpp"

class Client
{
public:
    Client(int ip,uint16_t port)
    :_is_runing(false)
    {
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(socket<0)
        {
            Log(FATAL,"client creates sockfd error\n");
            exit(-1);
        }
        Log(DEBUG,"client creates sockfd %d successfully\n",_sockfd);

        bzero(&_server_addr,sizeof(_server_addr));
        _server_addr.sin_family=AF_INET;
        _server_addr.sin_port=port;
        _server_addr.sin_addr.s_addr=ip;
        Log(DEBUG,"client init successfully\n");
    }

    void Send()
    {
        while(_is_runing)
        {
            char buf[1024];
            std::cin>>buf;
            if(0==strcmp("quit",buf))
            {
                _is_runing=false;
                Log(DEBUG,"client wants to quit\n");
            }
            int wn=sendto(_sockfd,buf,strlen(buf),0,(struct sockaddr*)(&_server_addr),sizeof(_server_addr));
            if(wn<=0)
            {
                Log(ERROR,"client writes error\n");
                return;
            }
        }
    }
    
    void Recv()
    {
        while(_is_runing)
        {
            char buf[1024];
            struct sockaddr_in server_addr;
            bzero(&server_addr,sizeof(server_addr));
            socklen_t len=sizeof(server_addr);
            int rn=recvfrom(_sockfd,buf,sizeof(buf)-1,0,(struct sockaddr*)(&server_addr),&len);
            if(rn<=0)
            {
                Log(ERROR,"client reads error\n");
                return;
            }
            buf[rn]=0;
            InetAddr addr(server_addr);
            //处理消息
            printf("%s\n",buf);
        }
    }

    void Start()
    {
        _is_runing=true;
        Pthread sp(std::bind(&Client::Send,this),"send_pthread");
        Pthread rp(std::bind(&Client::Recv,this),"recv_pthread");
        Log(DEBUG,"client launches scessfully\n");

        sp.Start();
        rp.Start();
        sp.Wait();
        rp.Wait();

        Log(DEBUG,"client quit successfully\n");
    }

    ~Client()
    {}

private:
    struct sockaddr_in _server_addr;
    int _sockfd;
    bool _is_runing;
};